#include "stdafx.h"
#include "Interpolation.h"
#include "config/InterpolationDefault.h"
#include "Math.h"

using namespace unigame;

float Interpolation::expOut(float time, float duration, float* param)
{
	if(time >= duration)
	{
		return 1;
	}
	if(time <= 0)
	{
		return 0;
	}
	float exp1 = EXP_BASE;
	float exp2 = EXP_MULTI;
	if(param)
	{
		exp1 = param[0];
		exp2 = param[1];
	}
	return 1 - powf(exp1, -exp2 * time / duration);
}

float Interpolation::expIn(float time, float duration, float* param)
{
	if(time >= duration)
	{
		return 1;
	}
	if(time <= 0)
	{
		return 0;
	}
	float exp1 = EXP_BASE;
	float exp2 = EXP_MULTI;
	if(param)
	{
		exp1 = param[0];
		exp2 = param[1];
	}
	return pow(exp1, exp2 * (time / duration - 1));
}

float Interpolation::expOutIn(float time, float duration, float* param)
{
	if(time >= duration)
	{
		return 1;
	}
	if(time <= 0)
	{
		return 0;
	}
	float exp1 = EXP_BASE;
	float exp2 = EXP_MULTI;
	if(param)
	{
		exp1 = param[0];
		exp2 = param[1];
	}
	if(time < duration / 2) 
	{
		return 0.5f * ( 1 - pow(exp1, -exp2 * 2 * time / duration));
	}
	return 0.5f * pow(exp1, exp2 * (time * 2 / duration - 2)) + 0.5f;
}

float Interpolation::expInOut(float time, float duration, float* param)
{
	if(time >= duration)
	{
		return 1;
	}
	if(time <= 0)
	{
		return 0;
	}
	float exp1 = EXP_BASE;
	float exp2 = EXP_MULTI;
	if(param)
	{
		exp1 = param[0];
		exp2 = param[1];
	}
	time /= duration / 2;
	if (time < 1)
		return 1 / 2 * pow(exp1, exp2 * (time - 1));
	--time;
	return 1 / 2 * (2 - pow(exp1, -exp2 * time));
}

float Interpolation::linear(float time, float duration, float* param)
{
	if(time >= duration)
	{
		return 1;
	}
	if(time <= 0)
	{
		return 0;
	}
	return time / duration;
}

float Interpolation::elasticOut(float time, float duration, float* param)
{
	if(time >= duration)
	{
		return 1;
	}
	if(time <= 0)
	{
		return 0;
	}
	float s;
	float amplitude = ELASTIC_AMPLITUDE;
	float period = ELASTIC_PERIOD;
	if(param)
	{
		amplitude = param[0];
		period = param[1];
	}
	if(amplitude < 1)
	{
		amplitude = 1;
		s = period / 4;
	}
	else
	{
		s = period / (2 * PI) * asin(1 / amplitude);
	}
	return (amplitude * pow(2, -10 * time / duration) * sin((time - s) * (2 * PI) / period) + 1);
}

float Interpolation::elasticIn(float time, float duration, float* param)
{
	if(time >= duration)
	{
		return 1;
	}
	if(time <= 0)
	{
		return 0;
	}
	float s;
	float amplitude = ELASTIC_AMPLITUDE;
	float period = ELASTIC_PERIOD;
	if(param)
	{
		amplitude = param[0];
		period = param[1];
	}
	if(amplitude < 1)
	{
		amplitude = 1;
		s = period / 4;
	}
	else
	{
		s = period / (2 * PI) * asin(1 / amplitude);
	}
	time /= duration;
	return -(amplitude * pow(2, 10 * (time -= 1)) * sin((time * duration - s) * (2 * PI) / period));
}

float Interpolation::elasticInOut(float time, float duration, float* param)
{
	if(time >= duration)
	{
		return 1;
	}
	if(time <= 0)
	{
		return 0;
	}
	float s;
	float amplitude = ELASTIC_AMPLITUDE;
	float period = ELASTIC_PERIOD * 1.5f;
	if(param)
	{
		amplitude = param[0];
		period = param[1];
	}
	if(amplitude < 1)
	{
		amplitude = 1;
		s = period / 4;
	}
	else
	{
		s = period / (2 * PI) * asin(1 / amplitude);
	}
	time /= duration / 2;
	if(time < 1) 
		return -0.5f * (amplitude * pow(2, 10 * (time -= 1)) * sin((time * duration - s) * (2 * PI) / period));
	return amplitude * pow(2, -10 * (time -= 1)) * sin((time * duration - s) * (2 * PI) / period) * 0.5f + 1;
}

float Interpolation::elasticOutIn(float time, float duration, float* param)
{
	if(time >= duration)
	{
		return 1;
	}
	if(time <= 0)
	{
		return 0;
	}
	float s;
	float amplitude = ELASTIC_AMPLITUDE;
	float period = ELASTIC_PERIOD;
	if(param)
	{
		amplitude = param[0];
		period = param[1];
	}
	if(amplitude < 0.5f)
	{
		amplitude = 0.5f;
		s = period / 4;
	}
	else
	{
		s = period / (2 * PI) * asin(0.5f / amplitude);
	}
	if(time < duration / 2) 
	{
		time /= duration / 2;
		return (amplitude * pow(2, -10 * time) * sin((time * duration - s) * (2 * PI) / period) + 0.5f);
	}
	time = time * 2 / duration - 1;
	return -(amplitude * pow(2, 10 * (time -= 1)) * sin((time * duration - s) * (2 * PI) / period)) + 0.5f;
}

float Interpolation::quarticOut(float time, float duration, float* param)
{
	if(time >= duration)
	{
		return 1;
	}
	if(time <= 0)
	{
		return 0;
	}
	time /= duration; 
	--time;
	return 1 - time * time * time * time;
}

float Interpolation::quarticIn(float time, float duration, float* param)
{
	if(time >= duration)
	{
		return 1;
	}
	if(time <= 0)
	{
		return 0;
	}
	time /= duration; 
	return time * time * time * time;
}

float Interpolation::quarticOutIn(float time, float duration, float* param)
{
	if(time >= duration)
	{
		return 1;
	}
	if(time <= 0)
	{
		return 0;
	}
	if(time < duration / 2)
	{
		time /= duration / 2;
		--time; 
		return -0.5f * (time * time * time * time - 1); 
	}
	time = time * 2 / duration - 1; 
	return 0.5f * time * time * time * time + 0.5f; 
}

float Interpolation::quarticInOut(float time, float duration, float* param)
{
	if(time >= duration)
	{
		return 1;
	}
	if(time <= 0)
	{
		return 0;
	}
	time /= duration / 2;
	if(time < 1)
	{
		return 0.5f * time * time * time * time;
	}
	time -= 2;
	return -0.5f * (time * time * time * time - 2);
}

float Interpolation::quinticOut(float time, float duration, float* param)
{
	if(time >= duration)
	{
		return 1;
	}
	if(time <= 0)
	{
		return 0;
	}
	time /= duration;
	--time;
	return 1 + time * time * time * time * time;
}

float Interpolation::quinticIn(float time, float duration, float* param)
{
	if(time >= duration)
	{
		return 1;
	}
	if(time <= 0)
	{
		return 0;
	}
	time /= duration; 
	return time * time * time * time * time; 
}

float Interpolation::quinticOutIn(float time, float duration, float* param)
{
	if(time >= duration)
	{
		return 1;
	}
	if(time <= 0)
	{
		return 0;
	}
	if(time < duration / 2)
	{
		time /= duration / 2;
		--time;
		return 0.5f * (time * time * time * time * time + 1); 
	}
	time = time * 2 / duration - 1;
	return 0.5f * time * time * time * time * time + 0.5f;
}

float Interpolation::quinticInOut(float time, float duration, float* param)
{
	if(time >= duration)
	{
		return 1;
	}
	if(time <= 0)
	{
		return 0;
	}
	time /= duration / 2;
	if(time < 1)
		return 0.5f * time * time * time * time * time;
	time -= 2;
	return 0.5f * (time * time * time * time * time + 2);
}

float Interpolation::sinusIn(float time, float duration, float* param)
{
	if(time >= duration)
	{
		return 1;
	}
	if(time <= 0)
	{
		return 0;
	}
	return -cos(time / duration * (PI / 2)) + 1; 
}

float Interpolation::sinusOut(float time, float duration, float* param)
{
	if(time >= duration)
	{
		return 1;
	}
	if(time <= 0)
	{
		return 0;
	}
	return sin(time / duration * (PI / 2));
}

float Interpolation::sinusInOut(float time, float duration, float* param)
{
	if(time >= duration)
	{
		return 1;
	}
	if(time <= 0)
	{
		return 0;
	}
	return -0.5f * (cos(PI * time / duration) - 1); 
}

float Interpolation::sinusOutIn(float time, float duration, float* param)
{
	if(time >= duration)
	{
		return 1;
	}
	if(time <= 0)
	{
		return 0;
	}
	if(time < duration / 2) 
	{
		return 0.5f * sin(time * 2 / duration * (PI / 2));
	}
	time = time * 2 / duration - 1;
	return 1 - 0.5f * cos(time * (PI / 2));
}

